local Msg = require("core.Msg")
local ObjHuman = require("core.ObjHuman")
local Obj = require("core.Obj")
local ObjMonster = require("core.ObjMonster")
local RoleExcel = require("excel.Role")
local ExpCalcConf = RoleExcel.expCalc
local BufferCmds = require("buffer.Cmds")
local Equip = require("bag.Equip")
local Cmds = require("buffer.Cmds")
local RoleFFI = require("role.RoleFFI")
local DailyActFL = require("activity.DailyActFL")
local ActDefine = require("activity.Define")
local Copy = require("copy.CopyL")
local MonthCardLogic = require("vip.MonthCardLogic")
local PetLogic = require("pet.PetLogic")
local FamilyLogicFL = require("family.FamilyLogicFL")

function init()
    ExpCalcConf.levelConf = {}
    ExpCalcConf.teamConf = {}
    for i = 1,#ExpCalcConf do
        local conf = ExpCalcConf[i]
        ExpCalcConf.levelConf[conf.level] = conf.level_value
        if conf.team > 0 then
            ExpCalcConf.teamConf[conf.team] = conf.team_value
        end
    end
end

-- 取杀怪经验加成值
function getKillMonsterExpAddValue(human)
    return Equip.getKillMonsterExpAddValue(human)
end

-- 取杀怪经验加成比率
function getKillMonaterExpAddRate(human)
    return Equip.getKillMonsterExpAddRate(human) + MonthCardLogic.getMonthMoreExp(human) + FamilyLogicFL.getFamilyWarExpAdd(human)
end

function calc(monster)
    if not monster or not monster.firstHitUuid or not ObjHuman.onlineUuid[monster.firstHitUuid] or
        ObjMonster.getValue(monster, "exp") == 0  then
        return 0
    end
    --获得经验值 = 怪物经验 × （1 + 组队经验加成比例 + 杀怪经验加成比率 + buffer经验加成比例） × 等级差经验修正 + 杀怪经验加成值
    local onlineUuid = ObjHuman.onlineUuid
    local monsterExp = ObjMonster.getExp(monster)
    local human = onlineUuid[monster.firstHitUuid]
    local needCalc, addExp
    local team = human.db.teamUuid 
    local teamLen = human.db.teamUuidLen
    local sumExp = 0
    local bufferExpRate = BufferCmds.passive.expRate(human)
    local conf = ObjMonster.get_conf(monster)
    local msgAddExp = Msg.gc.GC_MONSTER_ADD_EXP
    msgAddExp.objID = monster.id
    msgAddExp.flyCnt = conf.exp_fly_cnt

    local msgAddAwake = Msg.gc.GC_MONSTER_ADD_AWAKE
    msgAddAwake.objID = monster.id
    msgAddAwake.flyCnt = conf.awake_ball_cnt
    msgAddAwake.awake  = conf.awake_val

    local msgAddZhangong = Msg.gc.GC_MONSTER_ADD_ZHANGONG
    msgAddZhangong.objID = monster.id
    msgAddZhangong.flyCnt = conf.zhangong_fly_cnt
    msgAddZhangong.zhangong = conf.zhangong

    local preLv, nowLv
    local levelUp = 0

    if teamLen == 0 then  --无组队
        local copyID = Copy.isCopyBySceneID(human.scene_id)
        local LvRate = 0
        needCalc, addExp = needCalcExp(human, monster)
        if needCalc then
            LvRate = getLevelRate(human, monster)
            if DailyActFL.onCheckActCanJoin(human, ActDefine.ACT_TYPE_SHUANGBEI) and (not copyID or copyID == 415) then
                addExp = monsterExp * (2 +  getKillMonaterExpAddRate(human) + bufferExpRate) * LvRate + getKillMonsterExpAddValue(human)
            else
                addExp = monsterExp * (1 +  getKillMonaterExpAddRate(human) + bufferExpRate) * LvRate + getKillMonsterExpAddValue(human)
            end
        end
        local worldExpAdd = 0
        addExp = addExp or 0
        sumExp = addExp + worldExpAdd

        preLv = human.db.lv
        --exp
        local humanExp = ObjHuman.addExp(human, addExp, worldExpAdd, 1)
        nowLv  = human.db.lv
        msgAddExp.exp = humanExp or 0
        if msgAddExp.exp ~= 0 then
            levelUp = 0
            if preLv ~= nowLv then
                levelUp = 1
            end
            msgAddExp.levelUp = levelUp
            Msg.send(msgAddExp,human.fd)
        end
        if (conf.awake_control_lv == 0 or (preLv - ObjMonster.getLv(monster) <= conf.awake_control_lv)) and conf.awake_val > 0 and not Cmds.passive.awake(human) then
            ObjHuman.addAwake(human, conf.awake_val)
            Msg.send(msgAddAwake, human.fd)
        end

        if conf.zhangong > 0 then
            ObjHuman.addZhangong(human, conf.zhangong)
            Msg.send(msgAddZhangong, human.fd)
        end
    elseif teamLen > 0 then
        --组队经验
        for i = 1, teamLen do
            local memberUuid = team[i - 1].uuid
            if memberUuid then
                local target = onlineUuid[RoleFFI.ffi_string(memberUuid)]
                if target and Obj.canSeeEachOther(human, target) then
                    local copyID = Copy.isCopyBySceneID(target.scene_id)
                    local teamRate = 0
                    needCalc, addExp = needCalcExp(target, monster)
                    if needCalc then
                        local bufferExpRate = BufferCmds.passive.expRate(target)
                        teamRate = getTeamRate(target)
                        if DailyActFL.onCheckActCanJoin(target, ActDefine.ACT_TYPE_SHUANGBEI) and (not copyID or copyID == 415) then
                            addExp = monsterExp * (2 + teamRate + getKillMonaterExpAddRate(target) + bufferExpRate) * getLevelRate(target, monster) + getKillMonsterExpAddValue(target)
                        else
                            addExp = monsterExp * (1 + teamRate + getKillMonaterExpAddRate(target) + bufferExpRate) * getLevelRate(target, monster) + getKillMonsterExpAddValue(target)
                        end
                    end
                    local worldExpAdd = 0 
                    sumExp = (addExp or 0) + worldExpAdd
                    preLv = target.db.lv
                    --exp
                    local humanExp = ObjHuman.addExp(target, addExp, worldExpAdd, 1)
                    nowLv = target.db.lv
                    msgAddExp.exp = humanExp or 0
                    if msgAddExp.exp ~= 0 then
                        levelUp = 0
                        if preLv ~= nowLv then
                            levelUp = 1
                        end
                        msgAddExp.levelUp = levelUp
                        Msg.send(msgAddExp, target.fd)
                    end     
                end
            end
        end
    end
    PetLogic.addExp(human, monsterExp)
    return sumExp
end

local tmpmonster = {}
-- 得到当人击杀怪物时获得的经验值
function getSingleExp(human, monsterID)
    tmpmonster.monster_id = monsterID
    local monsterExp = ObjMonster.getExp(tmpmonster)
    local needCalc, addExp = needCalcExp(human, tmpmonster)
    if needCalc then
        local LvRate = getLevelRate(human, tmpmonster)
        local bufferExpRate = BufferCmds.passive.expRate(human)
        addExp = monsterExp * (1 +  getKillMonaterExpAddRate(human) + bufferExpRate) * LvRate + getKillMonsterExpAddValue(human)
    end
    addExp = addExp or 0
    return addExp
end

function needCalcExp(human,monster)
    local monsterConf = ObjMonster.get_conf(monster)
    local lv = human.db.lv - ObjMonster.getLv(monster)

    if monsterConf.full_exp == 1 then
        return true, nil
    end

    if lv > 0 and ((monsterConf.exp_control_lv ~= 0 and lv > monsterConf.exp_control_lv) or (lv >= ExpCalcConf[#ExpCalcConf].level)) then
        return false, ExpCalcConf[#ExpCalcConf].level_value
    end
    --local absLv = math.abs(lv)
    if lv < ExpCalcConf[#ExpCalcConf].level then
        return true, nil
    end
end

function getTeamCount(human, team)
    local onlineUuid = ObjHuman.onlineUuid
    local cnt = 0
    for i = 1, human.db.teamUuidLen do
        local memberUuid = team[i - 1].uuid
        if memberUuid and human.db._id ~= memberUuid then
            local target = onlineUuid[RoleFFI.ffi_string(memberUuid)]
            if target and Obj.canSeeEachOther(human, target) then
                cnt = cnt + 1
            end
        end
    end
    return cnt
end

local TEAM_LV = 10				-- 组队等级间隔
local TEAM_LV_RATE = 0.04		-- 组队等级加成率
local function getTeamLvCount(human, team)
    local onlineUuid = ObjHuman.onlineUuid
    local maxLv = 0
    for i = 1, human.db.teamUuidLen do
        local memberUuid = team[i - 1].uuid
        if memberUuid then
            local target = onlineUuid[RoleFFI.ffi_string(memberUuid)]
            if target then
                if Obj.canSeeEachOther(human, target) and target.db.lv > maxLv then
                    maxLv = target.db.lv
                end
            end
        end
    end

    if maxLv == 0 then
        return 0
    end

    local cnt = 0
    for i = 1, human.db.teamUuidLen do
        local memberUuid = team[i - 1].uuid
        if memberUuid then
            local target = onlineUuid[RoleFFI.ffi_string(memberUuid)]
            if target then
                if Obj.canSeeEachOther(human,target) and target.db.lv + TEAM_LV < maxLv then
                    cnt = cnt + 1
                end
            end
        end
    end

    return cnt
end

function getTeamRate(human)
    local team = human.db.teamUuid
    if not team then
        return 0
    end
    local count1 = getTeamCount(human, team)
    local count2 = getTeamLvCount(human, team)
    local rate1 = ExpCalcConf.teamConf[count1]			-- 组队人数加成
    local rate2 = count2 * TEAM_LV_RATE					-- 组队等级加成
    return rate1 or 0, rate2 or 0
end

function getLevelRate(human,monster)
    local monsterConf = ObjMonster.get_conf(monster)
    local lv = human.db.lv - ObjMonster.getLv(monster)
    if monsterConf.full_exp == 1 or lv < 0 then
        return 1
    end
    --local absLv = math.abs(lv)
    return ExpCalcConf.levelConf[lv]
end

init()
